# -*- coding: utf8 -*-
"""
Hopf algebra : intempt to describe some hopf algebra which
can be describe by polynomial realizations

AUTHOR:

- Jean-Baptiste Priez
"""
#*****************************************************************************
#       Copyright (C) 2012 Jean-Baptiste Priez <jbp@kerios.fr>,
#
#  Distributed under the terms of the GNU General Public License (GPL)
#
#    This code is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#    General Public License for more details.
#
#  The full text of the GPL is available at:
#
#                  http://www.gnu.org/licenses/
#*****************************************************************************
from sage.categories.category_types import Category_over_base_ring
from sage.categories.graded_hopf_algebras import GradedHopfAlgebras
from sage.misc.all import abstract_method
from sage.categories.realizations import RealizationsCategory

class GoodHopfAlgebras( Category_over_base_ring ):

    def super_categories( self ):
        R = self.base_ring()
        return [GradedHopfAlgebras( R )]


    class ParentMethods:

        @abstract_method
        def phi( self, indice ):
            '''
            std, pack or park
            '''

        @abstract_method
        def indices( self ):
            '''
            .. FIXME:: should be something like semigroups_generators no??
            permutations, packed words, parking functions
            '''

        @abstract_method
        def shift( self, ind1, ind2 ):
            '''
            The shift of the second indice uses to compute the shifted shuffle product.
            Examples for FQSym: ind2 := [1,2,3] is shifted of 3 if ind1 has size 3 : [4,5,6]
            For WQSym it's shifted of the max of ind1 (if ind1 := [1,1,2,2,2] and ind2 := [1,1,2]
            then ind2 is shifted of 2 -> [3,3,4]).
            Note the size of words is equivalent with the max in FQSym.
            For PQSym we use the size of ind1 (ind1 := [1,1,3,3] and ind2 := [1,2,2,4] imply ind2 becomes
            [5,6,6,8]). 
            
            .. EXAMPLES::
            
                sage: FQS = FQSym(QQ)
                sage: FQS.shift([1,2], [1])
                [3]
                sage: WQS = WQSym(QQ)
                sage: WQS.shift([1,1], [1,1,2])
                sage: [2,2,3]
                sage: PQS = PQSym(QQ)
                sage: PQS.shift([1,1], [1,1,2])
                sage: [3,3,4]
            '''

        @abstract_method
        def dual( self ):
            '''
            Return the Hopf algebra dual
            
            .. todo:: should be in Bigebra category...
            '''

    class Realizations( RealizationsCategory ):

        class ParentMethods:

            def _repr_( self ):
                """
                TESTS::
    
                    sage: F = FQSym(QQ).Fundamental();F
                    Hopf algebra of Free Quasi-Symmetric Functions over the Rational Field in the Fundamental basis
                """
                return "%s in the %s basis" % ( self.realization_of(), self._realization_name() )

            def phi( self, something_wordlike ):
                return self.realization_of().phi( something_wordlike )

            def indices ( self ):
                return self.realization_of().indices()

            def shift( self, ind1, ind2 ):
                return self.realization_of().shift( ind1, ind2 )

            def dual( self ):
                return self.realization_of().dual()

            def one_basis( self ):
                return self.indices()( [] )

            def coproduct_on_basis( self, indice ):
                '''
                .. should be in cogebra realization category ?
                '''
                from sage.categories.tensor import tensor
                F = self.realization_of().a_realization()
                return self.tensor_square().sum( 
                    coeff * tensor( ( self( F( u ) ), self( F( v ) ) ) )
                    for ( u, v ), coeff in F( self( indice ) ).coproduct() )

            def product_on_basis( self, indice1, indice2 ):
                '''
                .. should be in monoid ~ magma realization category or ...
                '''
                F = self.realization_of().a_realization()
                return self( F( self( indice1 ) ) * F( self( indice2 ) ) )

